/* typehints:start */
import { GameRoot } from "./root";
/* typehints:end */

import { copyObj, createID, getObjectType, isObjectValueEqual, randomNoArr } from "../core/utils/utils";
import GoodModules from "./goods/get_good";
import { attrDefine } from "./defines/attr_define";
import { Goods } from "./goods/goods";
import MD5 from "../core/utils/md5";
import { MoneyDefine } from "./defines/money_define";

const _id = createID();

export class BackDrop{
  constructor(root){
    /** @type {GameRoot} */
    this.root = root;

    this.data = {};
  }

  initialize(){
    this.root.sundryData.backdrop.map(item => {
      this.setData(item);
    })
  }

  saveData(){
    this.root.sundryData.backdrop = Object.values(this.data).map(item => {
      return item.getData();
    })

    this.root.saveSundryData();
    this.root.hud.parts.backpackPage.drawItems();
    this.root.hud.parts.worldPage.renderGood();
  }

  /**
   * 
   * @param {*} data 
   * @returns 
   */
  setData(data){
    let item = data;
    if(!(data instanceof Goods)){
      let good = GoodModules[data.key]
      if(!good) return;
      /** @type {Goods} */
      item = new good(this.root, null, data.attr);
      item.initialize(data.key);
    }

    // 如果这个物品需要存在世界，那么将其添加至世界
    if(item.attr.isLive){
      this.root.worldMap.goods.push(item);
    }

    let id = _id();
    // 将物品堆叠
    if(item.getIsStack()){
      id = this.getEqualGoodId(item);

      if(this.data[id]){
        this.data[id].attr.data.num = ~~(this.data[id].attr.data.num) + ~~(item.attr.data.num || 1);
      } else {
        this.data[id] = item;
      }
    } else {
      this.data[id] = item;
    }
    
    item.backpackId = id;
    return item;
  }

  /**
   * 获取相同的数据的good的id，堆叠物品
   * @param {*} item 
   */
  getEqualGoodId(item){
    let id = _id();

    let keys = Object.keys(this.data);
    for(let i = 0; i < keys.length; i++){
      let key = keys[i]
      let data = this.data[key];
      // 如果物品已经不存在于背包中并置于世界中，将不可堆叠
      if(item.attr.isLive || data.attr.isLive) {
        continue;
      }
      if(data.key == item.key 
        && isObjectValueEqual(data.attr.data, item.attr.data, ['num'])
      ){
        return key;
      }
    }

    return id;
  }

  getExistsGoods(){
    return Object.values(this.data).filter(item => {
      return !item.attr.isLive
    })
  }

  findKeyGoodNum(key, condition = false){
    let items = this.getExistsGoods();

    return items.filter(item => item.key == key && (!condition || condition(item))).reduce((a, b) => {
      return a + (b.num || 1);
    }, 0);
  }

  getAllWeight(){
    let kg = 0;
    
    this.getExistsGoods().map(good => {
      kg += (good.getAllWeight() || 1);
    })

    return kg;
  }

  // 保存一个新的内容
  put(item, isLog = true){
    let good = this.setData(item);

    if(isLog){
      this.root.message('infos', [
        `获取: <${good.getTitle()}>x${good.attr.data.num || 1}`
      ]);
    }

    this.saveData();
  }

  /**
   * 玩家获取金钱
   * @param {*} type 
   * @param {*} num 
   */
  playerGetMoney(type = MoneyDefine.money.key, num = 1){
    type = type == MoneyDefine.money.key ? MoneyDefine.money.key : MoneyDefine.stone.key;
    let money = this.root.mainPlayer.data[type];
    this.root.mainPlayer.data[type] = money + num;

    this.root.message('infos', [
      `获取: ${MoneyDefine[type].text}x${num}`
    ]);

    this.root.savePlayerData();
  }

  getGoodAndPut(key, data = {}, isLog = true){
    let item = null;
    // 根据传入的参数生成对应的物品实例
    if(getObjectType(key) == 'String'){
      item = this.root.worldMap.getGood(key, null, data);
    } else {
      item = key;
    }
    if(!item) return false;

    // 判断负重
    let kg = this.root.mainPlayer.getWeightKg();
    let currentKg = this.getAllWeight();
    let weight = item.getAllWeight();
  
    if(weight + currentKg > kg){
      this.root.gameState.dialogs.showWarning('获取失败', 
        `你的背包已经满了，请清理背包再做操作。<${item.getTitle()}${item.num > 1 ? 'x' + item.num : ''}>重量为${weight}kg。`);
      return false;
    }

    // 当放入背包时，物品将不会在世界中显示
    item.attr.isLive = false;

    this.put(item, isLog);
    return true;
  }

  // 丢弃一样物品到世界里
  discard(id, num = 1){
    let item = this.data[id];
    
    if(item.attr.data.num >= num){
      this.consume(id, num);
      
      let data = item.getData();
      let extraId = randomNoArr(Object.keys(this.root.itemData.extraGoods), 'extra_');
      
      data.attr.data.num = num;
      data.attr.isLive = true;
      data.attr.worldPos = this.root.mainPlayer.data.worldPos;
      data.attr.mapPos = this.root.mainPlayer.data.mapPos;
      this.root.itemData.extraGoods[extraId] = data;
      this.root.worldMap.createExtraGood(extraId, data);

      this.root.saveItemData();
      return true;
    } else {
      this.root.message('alert', `数量不足, 你只拥有${item.attr.data.num}个`);
      return false;
    }
  }

  // 消耗物品
  consume(id, num = 1){
    let item = this.data[id];

    if(!item){
      this.root.gameState.dialogs.showInfo('物品不存在', '没有找到对应物品，无法消耗');
      return;
    }

    if(item.attr.data.num >= num){
      item.attr.data.num -= num;

      // 如果数量已经为0，那么将其销毁
      if(item.attr.data.num <= 0){
        this.remove(id);
      } else {
        this.saveData();
      }
  
      return true;
    } else {
      this.root.message('alert', `数量不足, 你只拥有${item.attr.data.num}个`);
      return false;
    }
  }

  // 移除物品指定数量，不会被物品的质量等数据影响
  findGoodKeyCousume(key, num = 1, condition = false){
    let consumeNum = 0;
    let consumeItem = [];
    let data = Object.keys(this.data);
    for(let i = 0; i < data.length; i++){
      let id = data[i];
      let item = this.data[id];
      if(consumeNum >= num) break;
      if(item.key == key && (!condition || condition(item))){
        if(item.num >= num){
          this.consume(id, num);
          return true;
        } else {
          let itemNum = item.num;
          if(itemNum + consumeNum > num){
            itemNum = num - consumeNum;
          }
          consumeNum += itemNum;
          consumeItem.push({
            id, num: itemNum
          });
        }
      }
    }
    if(consumeNum >= num){
      consumeItem.map(item => {
        this.consume(item.id, item.num);
      });
      return true;
    }

    return false;
  }

  remove(id){
    this.data[id].attr.isLive = false;
    delete this.data[id];

    this.saveData();
  }
}